package com.smartstate.admin.biz.service.impl;

import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smartstate.admin.biz.convert.UserConvert;
import com.smartstate.admin.biz.dto.MyOAuth2AccessToken;
import com.smartstate.admin.biz.entity.bo.*;
import com.smartstate.admin.biz.entity.dto.UserDto;
import com.smartstate.admin.biz.entity.dto.UserSearchDto;
import com.smartstate.admin.biz.entity.vo.*;
import com.smartstate.admin.biz.eunm.CommonEnum;
import com.smartstate.admin.biz.mapper.*;
import com.smartstate.admin.biz.model.LoginUser;
import com.smartstate.admin.biz.properties.SecurityOAuth2ClientProperties;
import com.smartstate.admin.biz.service.RoleService;
import com.smartstate.admin.biz.service.UserService;
import com.smartstate.admin.biz.util.AgeUtils;
import com.smartstate.admin.biz.util.IpUtils;
import com.smartstate.admin.biz.util.UserUtils;
import com.smartstate.common.base.constants.BizConstants;
import com.smartstate.common.base.constants.GlobalsConstants;
import com.smartstate.common.base.exception.CommonException;
import com.smartstate.common.base.httpResult.ResultCode;
import com.smartstate.common.base.httpResult.ResultVO;
import com.smartstate.common.feign.client.AuthorityClient;
import com.smartstate.common.feign.entity.vo.EnterpriseVo;
import com.smartstate.common.util.DateTimeUtil;
import com.smartstate.common.util.UuidUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.core.ApplicationContext;
import org.apache.commons.lang3.LocaleUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

@Service("userService")
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private SecurityOAuth2ClientProperties securityOAuth2ClientProperties;
//    @Resource
//    private EnterpriseMapper enterpriseMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private DiscoveryClient discoveryClient;
    @Resource
    private AuthorityClient authorityClient;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private RoleService roleService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private PermissionServiceImpl permissionService;
    @Resource
    private PermissionMapper permissionMapper;
    @Resource
    private RestTemplate restTemplate;
    @Value("${server.port}")
    private String serverPort;
    @Autowired
    private HttpServletRequest request;

    @Override
    public LoginUserVo getPrincipal(String ip) {
        LoginUserVo loginUserVo = new LoginUserVo();
        LoginUser loginUser = UserUtils.getLoginUser();
        UserVo userVo = this.loadUserByUserId(loginUser.getId());
        log.error("用户id:{}企业编号:{}", loginUser.getId(), loginUser.getEnterpriseId());
        if (loginUser.getEnterpriseId().equals("3c6baf2e80a34e4ba97a9df031367dc6") && loginUser.getId().equals("3c6baf2e80a34e4ba97a9df031367dc6")) {
            HashMap<String, Object> queryMap = new HashMap<>();
            queryMap.put("IS_WEB",0);
            List<Permission> permissions = permissionMapper.selectByMap(queryMap);
            List<Tree<String>> permissionsTree = PermissionServiceImpl.getPermissionsTree(permissions);
            loginUserVo.setPermissionTree(permissionsTree);
        } else {
            Role role = roleService.getRoleByUserId(loginUser.getId());
            List<Tree<String>> permissionsTree = null;
            List<PermissionVo> authList = null;
            if (role != null) {
                authList = permissionService.findPermissionByUserId(loginUser.getId());
                permissionsTree = PermissionServiceImpl.getPermissionsVOTree(authList);
            }
            loginUserVo.setMenus(authList);
            loginUserVo.setPermissionTree(permissionsTree);
            loginUserVo.setSysUser(userVo);
        }
        // 更新用户登录信息
        User userInfo = new User();
        BeanUtils.copyProperties(userVo, userInfo);
        userInfo.setLastLoginIp(ip);
        userInfo.setLastLoginTime(LocalDateTime.now());
        userInfo.setUpdateTime(LocalDateTime.now());
        userInfo.setUpdateUser(UserUtils.getLoginUser().getId());
        this.updateUserInfo(userInfo);
        return loginUserVo;
    }

    @Override
    public LoginUserVo getAppPrincipal(String ip) {
        LoginUserVo loginUserVo = new LoginUserVo();
        LoginUser loginUser = UserUtils.getLoginUser();
        UserVo userVo = this.loadUserByUserId(loginUser.getId());
        log.error("用户id:{}企业编号:{}", loginUser.getId(), loginUser.getEnterpriseId());
        if (loginUser.getEnterpriseId().equals("3c6baf2e80a34e4ba97a9df031367dc6") && loginUser.getId().equals("3c6baf2e80a34e4ba97a9df031367dc6")) {
            HashMap<String, Object> queryMap = new HashMap<>();
            queryMap.put("IS_WEB",1);
            List<Permission> permissions = permissionMapper.selectByMap(queryMap);
            List<Tree<String>> permissionsTree = PermissionServiceImpl.getPermissionsTree(permissions);
            loginUserVo.setPermissionTree(permissionsTree);
        } else {
            Role role = roleService.getRoleByUserId(loginUser.getId());
            List<Tree<String>> permissionsTree = null;
            List<PermissionVo> authList = null;
            if (role != null) {
                authList = permissionService.findAppPermissionByUserId(loginUser.getId());
                permissionsTree = PermissionServiceImpl.getPermissionsVOTree(authList);
            }
            loginUserVo.setMenus(authList);
            loginUserVo.setPermissionTree(permissionsTree);
            loginUserVo.setSysUser(userVo);
        }
        // 更新用户登录信息
        User userInfo = new User();
        BeanUtils.copyProperties(userVo, userInfo);
        userInfo.setLastLoginIp(ip);
        userInfo.setLastLoginTime(LocalDateTime.now());
        userInfo.setUpdateTime(LocalDateTime.now());
        userInfo.setUpdateUser(UserUtils.getLoginUser().getId());
        this.updateUserInfo(userInfo);
        return loginUserVo;
    }

    @Override
    @Cacheable(value = GlobalsConstants.REDIS_USER_CACHE, unless = "#result == null", key = "T(com.smartstate.common.base.constants.GlobalsConstants).USER_KEY_PREFIX.concat(T(String).valueOf(#userId))")
    public UserVo loadUserByUserId(String userId) {
        return new UserVo().buildVo(baseMapper.selectById(userId));
    }

    @Override
    public boolean judgePassword(String id, String password) {
        User user = baseMapper.selectById(id);
        if (user != null) {
            return passwordEncoder.matches(password, user.getPassword());
        }
        return false;
    }

    @Override
    public List<UserVo> findUserVoList(String username) {
        return baseMapper.findUserVoList(username);
    }

    @Override
    public UserVo loginByPassword(String username, String password, String code, String randomStr) {
        // 根据登录名 查询
        User user = baseMapper.findByUserName(username);
        log.error("用户名:{}密码:{}企业编号:{}", username, password, code);
        Boolean result=passwordEncoder.matches(password, user.getPassword());
        log.info("result:"+result);
        if (passwordEncoder.matches(password, user.getPassword())) {
            String url = "http://127.0.0.1:" + this.serverPort + "/oauth/token?client_id="
                    + securityOAuth2ClientProperties.getClientId() + "&client_secret=" + securityOAuth2ClientProperties.getClientSecret()
                    + "&grant_type=password&scope=all&username=" + user.getId() + "&password=" + password;
            MyOAuth2AccessToken myOAuth2AccessToken = restTemplate.postForObject(url, null, MyOAuth2AccessToken.class);
            UserVo vo = new UserVo();
            BeanUtils.copyProperties(user, vo);
            Role roleByUserId = roleService.getRoleByUserId(user.getId());
            if (roleByUserId != null){
                vo.setRoleName(roleByUserId.getRoleName());
                vo.setRoleInfo(new RoleVo().buildVo(roleByUserId));
            }
            vo.setAccessToken(myOAuth2AccessToken.getAccess_token());
            // 记录登录日志
            if(null !=user) {
                if (StringUtils.isNotBlank(user.getDeptId())) {
                    String departmentName = userMapper.getDeptByID(user.getDeptId());
                    String chromAll = request.getHeader(CommonEnum.USERAGENT.getValue());
                    String chrom = null;
                    if (StringUtils.isNotBlank(chromAll)) {
                        chrom = chromAll.substring(chromAll.lastIndexOf(CommonEnum.RIGHTBRACKETS.getValue()) + 1, chromAll.length());
                    }
                    // 获取用户对应的角色数据
                    String roleName=userMapper.getRoleByName(username);
                    LoginLog loginLog = new LoginLog.LoginLogBuilder().setUsername(username).setRoleName(roleName)
                            .setNickname(user.getNickname()).setLoginTime(DateTimeUtil.currentDatetime()).setIp(IpUtils.getIP(request))
                            .setBrowser(chrom)
                            .setCreateUser(user.getNickname()).setCreateTime(LocalDateTime.now()).getLoginLog();
                    userMapper.addLoginLog(loginLog);
                }
            }
            return vo;
        }
        return null;
    }


    //  @CacheEvict(value = GlobalsConstants.REDIS_USER_CACHE, key = "T(com.smartstate.common.base.constants.GlobalsConstants).USER_KEY_PREFIX.concat(T(String).valueOf(#user.id))")
    //hcx 修改单个CacheEvict为多个，添加user-dictionary
    @Caching(evict = {
            @CacheEvict(value = GlobalsConstants.REDIS_USER_CACHE, key = "T(com.smartstate.common.base.constants.GlobalsConstants).USER_KEY_PREFIX.concat(T(String).valueOf(#id))"),
            @CacheEvict(value = "user-dictionary")
    })
    @Transactional(rollbackFor = CommonException.class)
    @Override
    public boolean updateUserInfo(User user) {
        return baseMapper.updateById(user) > 0;
    }

    @Override
    @Transactional(rollbackFor = CommonException.class)
    @Caching(evict = {
            @CacheEvict(value = GlobalsConstants.REDIS_USER_CACHE, key = "T(com.smartstate.common.base.constants.GlobalsConstants).USER_KEY_PREFIX.concat(T(String).valueOf(#id))"),
            @CacheEvict(value = "user-dictionary")
    })
    public boolean deleteUser(String id) {
        User user = new User();
        user.setId(id);
        user.setIsDeleted(BizConstants.SYS_NO);
        user.setUpdateTime(LocalDateTime.now());
        user.setUpdateUser(UserUtils.getLoginUser().getId());
        int i = baseMapper.updateById(user);
        int b = userRoleMapper.delete(new QueryWrapper<UserRole>().eq("USER_ID", id));
        return i > 0 && b > 0;
    }

    @Transactional(rollbackFor = CommonException.class)
    @Override
    @CacheEvict(value = "user-dictionary")
    public boolean deleteBatchUser(List<String> ids) {
        try {
            ids.forEach(this::deleteUser);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
        return true;
    }

    @Transactional(rollbackFor = CommonException.class)
    @Override
    public boolean updatePassword(UserDto userDto) {
        if (StringUtils.isBlank(userDto.getLoginUserId())) {
            userDto.setLoginUserId(UserUtils.getLoginUser().getId());
        }
        //检查原密码是否输入正确
        User user1 = baseMapper.selectById(userDto.getId());

        if (userDto.getUpdatePassword() == 1 && (userDto.getOriginalPassword() == null ||
                userDto.getOriginalPassword().isBlank() ||
                (!passwordEncoder.matches(userDto.getOriginalPassword(), user1.getPassword())))) {
            throw new CommonException(ResultCode.PASSWORD_ERROR);
        }
        User user = new User();
        user.setId(userDto.getId());
        user.setPassword(passwordEncoder.encode(userDto.getPassword()));
        user.setUpdateTime(LocalDateTime.now());
        user.setUpdateUser(userDto.getLoginUserId());
        return baseMapper.updateById(user) > 0;
    }


    @Override
    public IPage<UserVo> queryUserList(UserSearchDto userSearchDto) {
        userSearchDto.setEnterpriseId(UserUtils.getLoginUser().getEnterpriseId());
        Page page = userSearchDto.initPage();
        List<UserVo> userList = baseMapper.findUserListByCompany(page, userSearchDto);
        if (userList != null) {
            for (UserVo userVo : userList) {
                Role roleByUserId = roleMapper.getRoleByUserId(userVo.getId());
                if (roleByUserId != null) {
                    RoleVo roleVo = new RoleVo();
                    roleVo.buildVo(roleByUserId);
                    userVo.setRoleInfo(roleVo);
                }

            }
        }
        return page.setRecords(userList);
    }

    @Override
    @Transactional(rollbackFor = CommonException.class)
    //hcx 修改单个CacheEvict为多个，添加user-dictionary
    @Caching(evict = {
            @CacheEvict(value = GlobalsConstants.REDIS_USER_CACHE, key = "T(com.smartstate.common.base.constants.GlobalsConstants).USER_KEY_PREFIX.concat(T(String).valueOf(#id))"),
            @CacheEvict(value = "user-dictionary")
    })
    //@CacheEvict(value = GlobalsConstants.REDIS_USER_CACHE, key = "T(com.smartstate.common.base.constants.GlobalsConstants).USER_KEY_PREFIX.concat(T(String).valueOf(#id))")
    public boolean updateStatus(String id, Integer status) {
        User user = new User();
        user.setId(id);
        user.setStatus(status);
        user.setUpdateTime(LocalDateTime.now());
        user.setUpdateUser(UserUtils.getLoginUser().getId());
        return baseMapper.updateById(user) > 0;
    }

    /**
     * 创建新用户
     *
     * @param userDto
     * @return
     */
    @Transactional(rollbackFor = CommonException.class)
    @Override
    @CacheEvict(value = "user-dictionary")
    public User saveUser(UserDto userDto) {
        userDto.setLoginUserId(UserUtils.getLoginUser().getId());
        User user = UserConvert.buildBo(userDto);
        user.setCreateTime(LocalDateTime.now());
        if (StringUtils.isBlank(user.getEnterpriseId())) {
            user.setEnterpriseId(UserUtils.getLoginUser().getEnterpriseId());
        }
        {
            User user1 = this.baseMapper.selectByEnterpriseIdAndUsername(user.getEnterpriseId(), user.getUsername());
            if (user1 != null) {
                throw new CommonException("用户已存在", ResultCode.RESOURCE_EXISTS.getCode());
            }
        }
        {
            User user1 = this.baseMapper.selectByEnterpriseIdAndUsername(user.getEnterpriseId(), user.getUsername());
            if (StringUtils.isBlank(user.getPassword())) {
                throw new CommonException("密码不能为空", ResultCode.RESOURCE_NOT_EXISTS.getCode());
            }
        }

        user.setCreateUser(userDto.getLoginUserId());
        user.setUserType(BizConstants.HT);
        user.setIsDeleted(BizConstants.SYS_YES);
        user.setStatus(BizConstants.USER_STATUS_NORMAL);
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        Integer age = userDto.getAge();
        if (age != null && age >0 && age < 120 ){
            user.setAge(age);
        }
        //如果生日存在，根据生日计算生成年龄
        if (userDto.getBirthday() != null){
            try {
                Date birthDay = Date.from(user.getBirthday().atZone(ZoneId.systemDefault()).toInstant());
                int ageByBirth = AgeUtils.getAgeByBirth(birthDay);
                if (ageByBirth <0 || ageByBirth > 120){
                    throw new CommonException("日期输入错误，请重新输入", ResultCode.PARAMETER_ERROR.getCode());
                }
                user.setAge(ageByBirth);
            } catch (ParseException e) {
                throw new CommonException("日期输入错误，请重新输入", ResultCode.PARAMETER_ERROR.getCode());
            }
        }
        //新增用户
        int insert = baseMapper.insert(user);
        //绑定角色
        if (insert > 0 && StringUtils.isNotBlank(userDto.getRoleId())) {
            userDto.setId(user.getId());
            this.updateRole(userDto);
        }
        return user;
    }

    /**
     * 修改用户信息，修改用户信息是不允许改密码
     */
    @Transactional(rollbackFor = CommonException.class)
    @Caching(evict = {
            @CacheEvict(value = GlobalsConstants.REDIS_USER_CACHE, key = "T(com.smartstate.common.base.constants.GlobalsConstants).USER_KEY_PREFIX.concat(T(String).valueOf(#userDto.id))"),
            @CacheEvict(value = "user-dictionary")
    })
    @Override
    public boolean updateUser(UserDto userDto) {
        userDto.setLoginUserId(UserUtils.getLoginUser().getId());
        User user = UserConvert.buildBo(userDto);
        if (StringUtils.isBlank(user.getEnterpriseId())) {
            user.setEnterpriseId(UserUtils.getLoginUser().getEnterpriseId());
        }
        User user1 = this.baseMapper.selectByEnterpriseIdAndUsername(user.getEnterpriseId(), user.getUsername());
        if (user1 != null && !user1.getId().equals(user.getId())) {
            throw new CommonException("用户已存在", ResultCode.RESOURCE_EXISTS.getCode());
        }
        User ckUser = baseMapper.selectById(user.getId());
        user.setPassword(ckUser.getPassword());
        user.setUpdateTime(LocalDateTime.now());
        user.setUpdateUser(UserUtils.getLoginUser().getId());
        //如果生日存在，根据生日计算生成年龄
        if (userDto.getBirthday() != null){
            try {
                int ageByBirth = AgeUtils.getAgeByBirth(Date.from(user.getBirthday().atZone(ZoneId.systemDefault()).toInstant()));
                user.setAge(ageByBirth);
            } catch (ParseException e) {
                throw new CommonException("日期输入错误，请重新输入", ResultCode.PARAMETER_ERROR.getCode());
            }
        }
        if (StringUtils.isNotBlank(userDto.getRoleId())) {
            userDto.setId(user.getId());
            this.updateRole(userDto);
        }
        return baseMapper.updateById(user) > 0;
    }


    @Override
    public Map<String, Object> checkUserName(String username, String id) {
        Map<String, Object> map = new HashMap<>(16);
        if (StringUtils.isBlank(id)) {
            List<User> users = baseMapper.selectList(new QueryWrapper<User>().eq("USERNAME", username).eq("STATUS", BizConstants.USER_STATUS_NORMAL).eq("USER_TYPE", BizConstants.HT));
            if (users.size() > 0) {
                map.put("flag", false);
                map.put("msg", "用户登录名不能重复");
                return map;
            }
        } else {
            List<User> users = baseMapper.selectList(new QueryWrapper<User>().ne("ID", id).eq("USERNAME", username).eq("STATUS", BizConstants.USER_STATUS_NORMAL).eq("USER_TYPE", BizConstants.HT));
            if (users.size() > 0) {
                map.put("flag", false);
                map.put("msg", "用户登录名不能重复");
                return map;
            }
        }
        map.put("flag", true);
        return map;
    }

    @Override
    public Map<String, Object> checkNickname(String nickname, String id) {
        Map<String, Object> map = new HashMap<>(16);
        if (StringUtils.isBlank(id)) {
            List<User> users = baseMapper.selectList(new QueryWrapper<User>().eq("NICKNAME", nickname).eq("STATUS", BizConstants.USER_STATUS_NORMAL).eq("USER_TYPE", BizConstants.HT));
            if (users.size() > 0) {
                map.put("flag", false);
                map.put("msg", "用户昵称不能重复");
                return map;
            }
        } else {
            List<User> users = baseMapper.selectList(new QueryWrapper<User>().ne("ID", id).eq("NICKNAME", nickname).eq("STATUS", BizConstants.USER_STATUS_NORMAL).eq("USER_TYPE", BizConstants.HT));
            if (users.size() > 0) {
                map.put("flag", false);
                map.put("msg", "用户昵称不能重复");
                return map;
            }
        }
        map.put("flag", true);
        return map;
    }


    @Override
    public Map<String, Object> checkPhone(String phone, String id) {
        Map<String, Object> map = new HashMap<>(16);
        if (StringUtils.isBlank(id)) {
            List<User> userList = baseMapper.selectList(new QueryWrapper<User>().eq("PHONE", phone).eq("STATUS", BizConstants.USER_STATUS_NORMAL).eq("USER_TYPE", BizConstants.HT));
            if (userList.size() > 0) {
                map.put("flag", false);
                map.put("msg", "手机号不能重复");
                return map;
            }
        } else {
            List<User> userList = baseMapper.selectList(new QueryWrapper<User>().ne("ID", id).eq("PHONE", phone).eq("STATUS", BizConstants.USER_STATUS_NORMAL).eq("USER_TYPE", BizConstants.HT));
            if (userList.size() > 0) {
                map.put("flag", false);
                map.put("msg", "手机号不能重复");
                return map;
            }
        }
        map.put("flag", true);
        return map;
    }

    @Override
    public boolean updateRole(UserDto userDto) {
        UserRole userRole = userRoleMapper.selectOne(new QueryWrapper<UserRole>().eq("USER_ID", userDto.getId()));
        if (null == userRole) {
            UserRole userRole1 = new UserRole();
            userRole1.setId(UuidUtil.getUuid());
            userRole1.setUserId(userDto.getId());
            userRole1.setRoleId(userDto.getRoleId());
            return userRoleMapper.insert(userRole1) > 0;
        } else {
            if (!(userRole.getRoleId().equals(userDto.getRoleId()))) {
                userRole.setRoleId(userDto.getRoleId());
                return userRoleMapper.updateById(userRole) > 0;
            }
            return true;
        }
    }

    @Override
    public List<UserVo> getUserAll() {
        List<User> list = this.list(new QueryWrapper<User>().eq("IS_DELETED",0));
        List<UserVo> userVoList = new UserVo().buildVoList(list);
        return userVoList;
    }

    @Override
    public List<UserVo> selectBatchUser(List<String> idList) {
        List<User> users = userMapper.selectBatchIds(idList);
        if (null != users && users.size() > 0){
            List<UserVo> userVos = new UserVo().buildVoList(users);
            return userVos;
        }
        return null;
    }

    @Override
    public String getUserByUserName(String username) {
        User user = userMapper.selectOne(username);
        if (null != user){
            return user.getId();
        }
        return null;
    }


}